package AgentTravel.Behaviours;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.joda.time.LocalDate;

import AgentTravel.MyOntology;
import AgentTravel.LogicObjects.City;
import AgentTravel.LogicObjects.OtherUserInfo;
import AgentTravel.LogicObjects.Preferences;
import AgentTravel.LogicObjects.UserProfile;
import AgentTravel.LogicObjects.UserProfile.Gender;
import AgentTravel.LogicObjects.UserProfile.PreferredGender;
import AgentTravel.Messages.RejectVisitMessage;
import AgentTravel.Messages.RequestVisitMessage;

import jade.core.AID;
import jade.core.behaviours.Behaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;

public class VisitorOrganiseVisitBehaviour extends Behaviour 
{
	private City city;
	private List<LocalDate> days;
	private AID[] found;
	private Preferences myPreferences;
	private UserProfile myProfile;
	
	private Map<LocalDate, OtherUserInfo> planned=new HashMap<LocalDate,OtherUserInfo>();
	private Map<AID, UserProfile> hostsInfo=new HashMap<AID,UserProfile>();
	
	public VisitorOrganiseVisitBehaviour(City city, List<LocalDate> days2, Preferences preferences, UserProfile myProfile)
	{
		this.city=city;
		this.days=days2;
		this.myPreferences=preferences;
		this.myProfile=myProfile;
	}
		
	private int step = 0;
	public void action() 
	{
		switch (step) 
		{
			case 0:	
				//wyszukanie hostow i zgloszenie sie do nich
				DFAgentDescription template = new DFAgentDescription();
				ServiceDescription sd = new ServiceDescription();
				sd.setType(MyOntology.hostingService);
				sd.setName(city.getName());
				template.addServices(sd);
				try 
				{
					DFAgentDescription[] result = DFService.search(myAgent, template);
					found = new AID[result.length];
					for (int i = 0; i < result.length; ++i) 
					{
						found[i] = result[i].getName();
						if(!result[i].getName().equals(myAgent.getName()))
						{
							System.out.println("VISITOR: Wysylam requesta o profil");
							ACLMessage msg=new ACLMessage(ACLMessage.REQUEST);
							msg.addReceiver(found[i]);
							msg.setContent(MyOntology.requestProfileText);
							myAgent.send(msg);
						}
					}
				}
				catch (FIPAException fe) 
				{
					fe.printStackTrace();
				}
				step++;
				break;
			case 1:
				//odbieranie profili i potwierdzen / odrzucen od hostow
				//TODO: niezaleznie od tego odpowiadamy gdzies indziej na zapytania o profile
				
				System.out.println("Czekanie na odp od hostow");
				MessageTemplate mt=MessageTemplate.MatchPerformative(ACLMessage.INFORM);
				mt=MessageTemplate.or(mt, MessageTemplate.MatchPerformative(ACLMessage.INFORM_REF));
				
				MessageTemplate mt2=null;
				for(int i=0;i<found.length;i++)
				{
					if(mt2==null)
						mt2=MessageTemplate.MatchSender(found[i]);
					else
						mt2=MessageTemplate.or(mt2, MessageTemplate.MatchSender(found[i]));
				}
				
				if(mt2==null)
				{
					System.out.println("Nie ma od kogo odbierac!");
				}
				else
					mt=MessageTemplate.and(mt, mt2);
				
				ACLMessage msg = myAgent.receive(mt);
				
				if(msg!=null)
				{
					if(msg.getPerformative()==(ACLMessage.INFORM_REF))
					{
						System.out.println("VISITOR: Dostalem profil hosta");
						try 
						{
							UserProfile hisProfile=(UserProfile)msg.getContentObject();
							
							if(!this.hostsInfo.containsKey(msg.getSender()))
								hostsInfo.put(msg.getSender(), hisProfile);
							
							if(MatchesPreferences(hisProfile))
							{
								System.out.println("VISITOR: Host mi pasuje");
								ACLMessage request=new ACLMessage(ACLMessage.PROPOSE);
								request.addReceiver(msg.getSender());
								request.setContentObject(new RequestVisitMessage(days));
								myAgent.send(request);
							}
							else
								System.out.println("VISITOR: Nie pasuje mi host");
						} 
						catch (UnreadableException e) 
						{							
							e.printStackTrace();
						}
						catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					else if(msg.getContent().startsWith(MyOntology.reservationAnswer))
					{
						System.out.println("VISITOR: Dostalem odpowiedz od hosta");
						System.out.println(msg.getContent());
						
						String ans=msg.getContent();
						
						for(int i=0;i<days.size();i++)
						{
							if(ans.contains("_"+i+"_"))
							{
								if(planned.containsKey(days.get(i)))
								{
									//odwolywanie jezeli ktos potwierdzil
									//TODO: mozliwe ze to jest niepotrzebne
									ACLMessage discard=new ACLMessage(ACLMessage.REJECT_PROPOSAL);
									discard.addReceiver(msg.getSender());
									try {
										discard.setContentObject(new RejectVisitMessage(days.get(i),myProfile));
										myAgent.send(discard);
									} catch (IOException e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
									
								}
								else
								{
									//fajnie
									planned.put(days.get(i), 
											new OtherUserInfo(msg.getSender(),hostsInfo.get(msg.getSender()),false));
								}
							}
						}
						if(planned.size()==days.size())
							step++;
					}
					
				}
				else
					block();
				break;
			case 2:
				
				System.out.println("VISITOR: Zalatwilem sobie nocleg w "+city.getName()+" !!! :):):)");
				
				Iterator<LocalDate> iter=planned.keySet().iterator();
				int i=0;
				while(iter.hasNext())
				{
					i++;
					LocalDate cln=iter.next();
					System.out.println("Dnia "+ i+" spie u "+planned.get(cln).contactAgent.getName());
					
					for(int k=0;k<found.length;k++)
					{
						//odwolywanie wszystkich innych
						if(!found[k].equals(planned.get(cln).contactAgent))
						{
							ACLMessage discard=new ACLMessage(ACLMessage.REJECT_PROPOSAL);
							discard.addReceiver(found[k]);
							try {
								discard.setContentObject(new RejectVisitMessage(days.get(i-1),myProfile));
								myAgent.send(discard);
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
					}
				}
				step++;
				break;
			}
		}
	
		private boolean MatchesPreferences(UserProfile hisProfile) 
		{
			//TODO: bullshit
			return true;
			
//			if(hisProfile.getAge()<myPreferences.getMinAge())
//				return false;
//			if(hisProfile.getAge()>myPreferences.getMaxAge())
//				return false;
//			
//			PreferredGender pg=myPreferences.getPreferredGender();
//			if(pg!=PreferredGender.Both &&
//					((pg==PreferredGender.Femal && hisProfile.getMyGender()==Gender.Male) || 
//					(pg==PreferredGender.Male && hisProfile.getMyGender()==Gender.Female)))
//				return false;
//			
//			boolean langOk=false;
//			for(int i=0;i<myPreferences.getAcceptableLanguages().size();i++)
//			{
//				if(hisProfile.getLanguages().
//						containsKey(myPreferences.getAcceptableLanguages().get(i)))
//					langOk=true;
//			}
//			
//			//TODO: chwilowo wylaczone
//			//if(!langOk)
//			//	return false;
//						
//			return true;
		}

		public boolean done() 
		{
			return step == 3;
		}
	}
